#include "configManager.h"

namespace ED {
namespace Base {

ConfigManager &ConfigManager::GetInstance()
{
    static ConfigManager instance;
    return instance;
}

ConfigManager::ConfigManager() {}

ConfigManager::~ConfigManager() {}

int32_t ConfigManager::RegisterListener(const std::string &key, std::function<void(const nlohmann::json &)> listener)
{
    int listenerId = nextListenerId_++;
    listeners_[key][listenerId] = listener;
    return listenerId;
}

void ConfigManager::UnregisterListener(const std::string &key, int listenerId)
{
    if (listeners_.find(key) != listeners_.end()) {
        listeners_[key].erase(listenerId);
        if (listeners_[key].empty()) {
            listeners_.erase(key);
        }
    }
}

void ConfigManager::NotifyListeners(const std::string &key, const nlohmann::json &value)
{
    if (listeners_.find(key) != listeners_.end()) {
        for (auto &listener : listeners_[key]) {
            listener.second(value);
        }
    }
}

bool ConfigManager::LoadConfig(const std::string &filename)
{
    filename_ = filename;
    if (!LoadConfigFromFile(filename)) {
        printf("Failed to load config file: %s\n", filename.c_str());
        if (!LoadConfigFromFile(filename + ".bak")) {
            printf("Failed to load backup config file: %s\n", filename.c_str());
        }
    }
    return true;
}

bool ConfigManager::LoadConfigFromFile(const std::string &filename)
{
    std::ifstream file(filename);
    if (file.is_open()) {
        std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();
        std::lock_guard<std::mutex> lock(mutex_);
        config_ = nlohmann::json::parse(fileContent, nullptr, false);
        if (config_.is_discarded()) {
            return false;
        }
    } else {
        return false;
    }
    return true;
}

bool ConfigManager::SaveConfig(const std::string &filename)
{
    if (!SaveConfigToFile(filename)) {
        return false;
    }
    BackupConfig(filename);
    return true;
}

bool ConfigManager::SaveConfigToFile(const std::string &filename)
{
    std::ofstream file(filename);
    if (file.is_open()) {
        std::lock_guard<std::mutex> lock(mutex_);
        file << config_.dump(4);
        file.close();
        return true;
    } else {
        std::cerr << "Failed to open file: " << filename << std::endl;
        return false;
    }
}

void ConfigManager::BackupConfig(const std::string &filename)
{
    std::string backupFilename = filename + ".bak";
    std::ifstream src(filename, std::ios::binary);
    std::ofstream dst(backupFilename, std::ios::binary);
    dst << src.rdbuf();
    src.close();
    dst.close();
}

nlohmann::json ConfigManager::GetConfig(const std::string &key)
{
    std::lock_guard<std::mutex> lock(mutex_);
    auto it = config_.find(key);
    if (it != config_.end()) {
        return it.value();
    } else {
        std::cerr << "Key not found: " << key << std::endl;
        return {};
    }
}

bool ConfigManager::SetConfig(const std::string &key, const nlohmann::json &value)
{
    {
        std::lock_guard<std::mutex> lock(mutex_);
        config_[key] = value;
    }
    NotifyListeners(key, value);
    SaveConfig(filename_);
    return true;
}

} // namespace Base
} // namespace ED